package api

import (
	"config-client-v1/model"
	"config-client-v1/utils/tools"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/gin-gonic/gin/binding"
	"strings"
	"time"
)

type VariableController struct {
}

func (con VariableController) RecordList(ctx *gin.Context) {
	userToken := GetUserToken(ctx)
	param := struct {
		Addr string `json:"addr" binding:"max=20"`
		model.QueryData
	}{}
	err := ctx.ShouldBindBodyWith(&param, binding.JSON)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数",
			"data":    err.Error(),
		})
		return
	}
	param.TimeHandle(0)

	tx := model.DB.Model(&model.VarRecord{}).Where("project_id = ?", userToken.ProjectID)
	if param.StartTime != "" {
		tx.Where("create_time >= ?", param.StartTime)
	}
	if param.EndTime != "" {
		tx.Where("create_time <= ?", param.EndTime)
	}
	if param.Addr != "" {
		tx.Where("addr = ?", param.Addr)
	}
	var count int64
	list := make([]*model.VarRecord, 0)
	err = tx.Count(&count).Error
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    6,
			"message": err.Error(),
		})
		return
	}
	err = tx.Order("create_time DESC").Offset(param.StartPage()).Limit(param.PageSize).Find(&list).Error
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    6,
			"message": err.Error(),
		})
		return
	}
	//tools.SliceReverse(&list)
	ctx.JSON(200, gin.H{
		"code":    0,
		"message": "success",
		"data": map[string]interface{}{
			"list":  list,
			"count": count,
		},
	})
}

func (con VariableController) VariablesSlimList(ctx *gin.Context) {
	userToken := GetUserToken(ctx)
	param := struct {
		PPEID      int    `json:"ppe_id"`
		FSID       int    `json:"fs_id"`
		FrameType  string `json:"frame_type"`
		FieldName  string `json:"field_name" binding:"max=30"`
		Addr       string `json:"addr" binding:"max=20"`
		SpecType   string `json:"spec_type" binding:"max=20"`
		ModuleType string `json:"module_type" binding:"max=20"`
		SelectMode string `json:"select_mode"`
		model.QueryData
	}{}
	err := ctx.ShouldBindBodyWith(&param, binding.JSON)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数",
			"data":    err.Error(),
		})
		return
	}

	tx := model.DB.Model(&model.VariableSlim{})
	tx.Where("project_id = ?", userToken.ProjectID)
	if param.PPEID != 0 {
		tx.Where("ppe_id = ?", param.PPEID)
	}
	if param.FSID != 0 {
		tx.Where("fs_id = ?", param.FSID)
	}
	if param.ModuleType != "" {
		code2, ok := model.AllowFSCode2[param.ModuleType]
		if !ok {
			ctx.JSON(200, gin.H{
				"code":    2,
				"message": "无效的参数 module_type",
				"data": map[string]interface{}{
					"module_type": model.AllowModelCode2,
				},
			})
			return
		}
		tx.Where("code2 = ?", code2)
	}
	if param.FieldName != "" {
		tx.Where("field_name like ?", "%"+param.FieldName+"%")
	}
	if param.Addr != "" {
		tx.Where("addr like ?", "%"+param.Addr+"%")
	}
	if param.SpecType != "" {
		tx.Where("spec_type = ?", param.SpecType)
	}
	if param.FrameType != "" {
		ids := GetFrameIdByType(param.FrameType)
		tx.Where("frame_id in ?", ids)
	}

	var count int64
	list := make([]model.VariableSlim, 0)
	err = tx.Count(&count).Error
	//str := model.DB.ToSQL(func(tx *gorm.DB) *gorm.DB {
	//	return tx.Model(&model.VariableSlim{}).Where("fs_id = ?", param.FSID).Count(&count)
	//})
	//fmt.Printf("原生SQL语句: %s\n", str)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    6,
			"message": err.Error(),
		})
		return
	}

	err = tx.Order("id desc").Offset(param.StartPage()).Limit(param.PageSize).Find(&list).Error
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    6,
			"message": err.Error(),
		})
		return
	}

	ctx.JSON(200, gin.H{
		"code":    0,
		"message": "success",
		"data": map[string]interface{}{
			"list":  list,
			"count": count,
		},
	})
}

// VariablesPointList tag 数据查询
func (con VariableController) VariablesPointList(ctx *gin.Context) {
	userToken := GetUserToken(ctx)
	param := struct {
		Addrs    string `json:"addrs" binding:"max=1024"` // 变量地址,多个用逗号隔开
		Interval int    `json:"interval"`                 // 间隔秒
		model.QueryData
	}{}
	if param.PageIndex == 0 {
		param.PageIndex = 1
	}
	if param.PageSize == 0 {
		param.PageSize = 50000
	}
	err := ctx.ShouldBindBodyWith(&param, binding.JSON)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数",
			"data":    err.Error(),
		})
		return
	}
	param.TimeHandle(0)
	tx := model.DB.Model(&model.VarRecord{}).Where("project_id = ?", userToken.ProjectID)
	if param.StartTime == "" || param.EndTime == "" {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "请选择时间范围",
		})
		return
	}
	tx.Where("create_time >= ?", param.StartTime)
	tx.Where("create_time <= ?", param.EndTime)
	if param.Addrs != "" {
		addrs := strings.Split(param.Addrs, ",")
		tx.Where("addr in ?", addrs)
	}

	var count int64
	list := make([]*model.VarRecord, 0)
	err = tx.Count(&count).Error
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    6,
			"message": err.Error(),
		})
		return
	}
	err = tx.Order("create_time DESC").Offset(param.StartPage()).Limit(param.PageSize).Find(&list).Error
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    6,
			"message": err.Error(),
		})
		return
	}
	//tools.SliceReverse(&list)
	ctx.JSON(200, gin.H{
		"code":    0,
		"message": "success",
		"data": map[string]interface{}{
			"list":  list,
			"count": count,
		},
	})
}

type TableColumn struct {
	Label string `json:"label"` // 字段名
	Prop  string `json:"prop"`  // 字段key
}

// VariablesPointListV2 tag 数据查询; 动态列版本
func (con VariableController) VariablesPointListV2(ctx *gin.Context) {
	userToken := GetUserToken(ctx)
	param := struct {
		Addrs    string `json:"addrs" binding:"max=1024"`    // 变量地址,多个用逗号隔开
		Interval int    `json:"interval" binding:"required"` // 间隔秒
		model.QueryData
	}{}
	if param.PageIndex == 0 {
		param.PageIndex = 1
	}
	if param.PageSize == 0 {
		param.PageSize = 50000
	}
	err := ctx.ShouldBindBodyWith(&param, binding.JSON)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数",
			"data":    err.Error(),
		})
		return
	}
	param.TimeHandle(0)
	if param.StartTime == "" || param.EndTime == "" {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "请选择时间范围",
		})
		return
	}
	t1 := tools.StrToTime(param.StartTime)
	t2 := tools.StrToTime(param.EndTime)
	if t1.After(t2) {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "请选择正确的时间范围",
		})
		return
	}
	xLine := make([]string, 0)
	for {
		if t1.After(t2) {
			break
		}
		xLine = append(xLine, t1.Format("2006-01-02 15:04:05"))
		t1 = t1.Add(time.Second * time.Duration(param.Interval))
	}

	if param.Addrs == "" {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "请选择tags",
		})
		return
	}
	addrs := strings.Split(param.Addrs, ",")
	tableData := make([]map[string]interface{}, 0)
	tableColumns := make([]*TableColumn, 0)
	addrList := make([]*model.FrameItem, 0)
	_ = model.DB.Where("project_id = ? AND addr in ?", userToken.ProjectID, addrs).Select("addr,field_name").Find(&addrList).Error
	if len(addrList) != len(addrs) {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "请选择正确的tags",
		})
		return
	}

	tx := model.DB.Model(&model.VarRecord{}).Where("project_id = ?", userToken.ProjectID)
	tx.Where("create_time >= ?", param.StartTime)
	tx.Where("create_time <= ?", param.EndTime)
	tx.Where("addr in ?", addrs)

	list := make([]*model.VarRecord, 0)
	err = tx.Order("create_time ASC").Select("addr,value,create_time").Offset(param.StartPage()).Limit(param.PageSize).Find(&list).Error
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    6,
			"message": err.Error(),
		})
		return
	}

	points := make(map[string]*Point)
	tableColumns = append(tableColumns, &TableColumn{
		Label: "时间",
		Prop:  fmt.Sprintf("create_time"),
	})
	for key, addr := range addrs {
		fieldName := ""
		for _, row := range addrList {
			if row.Addr == addr {
				fieldName = row.FieldName
				break
			}
		}
		points[addr] = &Point{
			Addr:      addr,
			FieldName: fieldName,
			Data:      make([]float64, 0),
		}
		tableColumns = append(tableColumns, &TableColumn{
			Label: fieldName,
			Prop:  fmt.Sprintf("value%d", key),
		})
	}

	complexRate := 0     // 复杂度
	blockStartIndex := 0 // 下次时段数据查询的起始位置
	for i := 0; i < len(xLine); i++ {
		tStart := xLine[i] // 当前时段的开始时间
		tEnd := ""         // 当前时段的结束时间
		if i == len(xLine)-1 {
			tEnd = tools.StrToTime(tStart).Add(time.Second * time.Duration(param.Interval)).Format("2006-01-02 15:04:05")
		} else {
			tEnd = xLine[i+1]
		}
		tmpM := make(map[string]interface{})
		tmpM["create_time"] = tStart
		blockData := make([]*model.VarRecord, 0) // 为当前时段的全部数据
		for j := blockStartIndex; j < len(list); j++ {
			complexRate++
			if *(list[j].CreateTime) < tStart {
				continue
			}
			if *(list[j].CreateTime) >= tEnd {
				blockStartIndex = j
				break
			}
			blockData = append(blockData, list[j])
		}
		for key2, addr2 := range addrs {
			tmpV := float64(0)
			matched := false
			for _, row2 := range blockData {
				complexRate++
				if row2.Addr == addr2 {
					tmpV = row2.Value
					matched = true
					break
				}
			}
			if !matched && len(points[addr2].Data) > 0 {
				tmpV = points[addr2].Data[len(points[addr2].Data)-1] // 当前时段没有数据, 则取上一次的值
			}
			points[addr2].Data = append(points[addr2].Data, tmpV)
			tmpM[fmt.Sprintf("value%d", key2)] = tmpV
		}
		tableData = append(tableData, tmpM)
	}

	//tools.SliceReverse(&list)
	ctx.JSON(200, gin.H{
		"code":    0,
		"message": "success",
		"data": map[string]interface{}{
			//"xLine":        xLine,
			"tableData":    tableData,
			"tableColumns": tableColumns,
		},
	})
}

type Point struct {
	Addr      string    `json:"addr"`       // 变量地址
	FieldName string    `json:"field_name"` // 变量名
	Data      []float64 `json:"data"`
}

// TendencyChart tag 趋势图
func (con VariableController) TendencyChart(ctx *gin.Context) {
	userToken := GetUserToken(ctx)
	param := struct {
		Addrs    string `json:"addrs" binding:"max=1024"`    // 变量地址,多个用逗号隔开
		Interval int    `json:"interval" binding:"required"` // 间隔秒
		model.QueryData
	}{}
	if param.PageIndex == 0 {
		param.PageIndex = 1
	}
	if param.PageSize == 0 {
		param.PageSize = 50000
	}
	err := ctx.ShouldBindBodyWith(&param, binding.JSON)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数",
			"data":    err.Error(),
		})
		return
	}
	param.TimeHandle(0)
	if param.StartTime == "" || param.EndTime == "" {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "请选择时间范围",
		})
		return
	}
	t1 := tools.StrToTime(param.StartTime)
	t2 := tools.StrToTime(param.EndTime)
	if t1.After(t2) {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "请选择正确的时间范围",
		})
		return
	}
	xLine := make([]string, 0)
	for {
		if t1.After(t2) {
			break
		}
		xLine = append(xLine, t1.Format("2006-01-02 15:04:05"))
		t1 = t1.Add(time.Second * time.Duration(param.Interval))
	}

	if param.Addrs == "" {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "请选择tags",
		})
		return
	}
	addrs := strings.Split(param.Addrs, ",")

	addrList := make([]*model.FrameItem, 0)
	_ = model.DB.Where("project_id = ? AND addr in ?", userToken.ProjectID, addrs).Select("addr,field_name").Find(&addrList).Error
	if len(addrList) != len(addrs) {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "请选择正确的tags",
		})
		return
	}

	tx := model.DB.Model(&model.VarRecord{}).Where("project_id = ?", userToken.ProjectID)
	tx.Where("create_time >= ?", param.StartTime)
	tx.Where("create_time <= ?", param.EndTime)
	tx.Where("addr in ?", addrs)

	list := make([]*model.VarRecord, 0)
	err = tx.Order("create_time ASC").Select("addr,value,create_time").Offset(param.StartPage()).Limit(param.PageSize).Find(&list).Error
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    6,
			"message": err.Error(),
		})
		return
	}

	points := make(map[string]*Point)
	for _, addr := range addrs {
		fieldName := ""
		for _, row := range addrList {
			if row.Addr == addr {
				fieldName = row.FieldName
				break
			}
		}
		points[addr] = &Point{
			Addr:      addr,
			FieldName: fieldName,
			Data:      make([]float64, 0),
		}
	}

	complexRate := 0     // 复杂度
	blockStartIndex := 0 // 下次时段数据查询的起始位置
	for i := 0; i < len(xLine); i++ {
		tStart := xLine[i] // 当前时段的开始时间
		tEnd := ""         // 当前时段的结束时间
		if i == len(xLine)-1 {
			tEnd = tools.StrToTime(tStart).Add(time.Second * time.Duration(param.Interval)).Format("2006-01-02 15:04:05")
		} else {
			tEnd = xLine[i+1]
		}

		blockData := make([]*model.VarRecord, 0) // 为当前时段的全部数据
		for j := blockStartIndex; j < len(list); j++ {
			complexRate++
			if *(list[j].CreateTime) < tStart {
				continue
			}
			if *(list[j].CreateTime) >= tEnd {
				blockStartIndex = j
				break
			}
			blockData = append(blockData, list[j])
		}
		for _, addr2 := range addrs {
			tmpV := float64(0)
			matched := false
			for _, row2 := range blockData {
				complexRate++
				if row2.Addr == addr2 {
					tmpV = row2.Value
					matched = true
					break
				}
			}
			if !matched && len(points[addr2].Data) > 0 {
				tmpV = points[addr2].Data[len(points[addr2].Data)-1] // 当前时段没有数据, 则取上一次的值
			}
			points[addr2].Data = append(points[addr2].Data, tmpV)
		}
	}

	for _, point := range points {
		point.Data = point.Data[:len(point.Data)-1]
	}

	xLine = xLine[:len(xLine)-1]
	//tools.SliceReverse(&list)
	ctx.JSON(200, gin.H{
		"code":    0,
		"message": "success",
		"data": map[string]interface{}{
			"xLine":       xLine,
			"complexRate": complexRate,
			"points":      points,
		},
	})
}

func (con VariableController) Shield(ctx *gin.Context) {
	userToken := GetUserToken(ctx)
	param := struct {
		Addr  string `json:"addr" binding:"required"`
		Value uint8  `json:"value"`
	}{}
	err := ctx.ShouldBindBodyWith(&param, binding.JSON)
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "无效的参数",
			"data":    err.Error(),
		})
		return
	}
	if !model.AllowBoolean[param.Value] {
		ctx.JSON(200, gin.H{
			"code":    2,
			"message": "屏蔽值value只能是0或1",
		})
		return
	}
	addrs := strings.Split(param.Addr, ",")
	variableList := make([]*model.Variable, 0)
	err = model.DB.Where("project_id = ? AND addr in ?", userToken.ProjectID, addrs).Find(&variableList).Error
	if err != nil {
		ctx.JSON(200, gin.H{
			"code":    6,
			"message": err.Error(),
		})
		return
	}
	errorList := make([]map[string]interface{}, 0)
	for _, variable := range variableList {
		err = model.DB.Model(&model.Variable{}).Where("id = ?", variable.ID).Update("shield", param.Value).Error
		if err != nil {
			ctx.JSON(200, gin.H{
				"code":    6,
				"message": err.Error(),
			})
			return
		}
		v, ok := model.VariablesMap.Get(param.Addr)
		if ok {
			v.Shield = param.Value
		}
		if variable.FSID > 0 && variable.ChannelType == "AI" {
			errorList = append(errorList, map[string]interface{}{
				"addr": variable.Addr,
				"msg":  "当前变量是AI类型,已下发给自研设备",
			})
			_, _ = model.UpdateAQDQShieldSingle(variable, float64(param.Value))
		}
	}

	ctx.JSON(200, gin.H{
		"code":    0,
		"message": "success",
		"data":    map[string]interface{}{},
	})
}
